package org.jeecg.modules.utils;

import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.constant.BikeConstant;
import org.springframework.stereotype.Component;

import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Objects;

/**
 * 月月鸟
 */
@Component
public class MD5Utils {



    /**
     * 加密文件 byte[] 转为 32为 加密字符
     * @param str
     * @return 异或加密字符串
     */
    public static String bytesToMd5String(byte[] str) {
        try {
            // 生成一个MD5加密计算摘要
            MessageDigest md = MessageDigest.getInstance("MD5");
            // 计算md5函数
            md.update(str);
            // digest()最后确定返回md5 hash值，返回值为8为字符串。因为md5 hash值是16位的hex值，实际上就是8位的字符
            // BigInteger函数则将8位的字符串转换成16位hex值，用字符串来表示；得到字符串形式的hash值
            String md5=new BigInteger(1, md.digest()).toString(16);
            //BigInteger会把0省略掉，需补全至32位
            //异或加密
            return stringToXor(fillMD5(md5));
        } catch (Exception e) {
            throw new RuntimeException("MD5加密错误:"+e.getMessage(),e);
        }
    }
    /**
     * 加密文件 byte[] 转为 32为 加密字符
     * @param md5
     * @return string 异或加秘 字符串
     */
    private static String stringToXor(String md5) {
        byte[] md5ValueHex = hex2Bytes(md5);
        for(int i = 0; i < 16; i++){
            int n = md5ValueHex[i] ^ 0x7F;
            md5ValueHex[i] = (byte)n;
        }
        return bytes2HexString(md5ValueHex);
    }

    /**
     * 加密文件 byte[] 转为 32为 加密字符
     * @param str
     * @return 异或加密字符串
     */
    public static String bytesToMd5PileString(byte[] str) {
        try {
            // 生成一个MD5加密计算摘要
            MessageDigest md = MessageDigest.getInstance("MD5");
            // 计算md5函数
            md.update(str);
            // digest()最后确定返回md5 hash值，返回值为8为字符串。因为md5 hash值是16位的hex值，实际上就是8位的字符
            // BigInteger函数则将8位的字符串转换成16位hex值，用字符串来表示；得到字符串形式的hash值
            String md5=new BigInteger(1, md.digest()).toString(16);
            //BigInteger会把0省略掉，需补全至32位
            //异或加密
            return stringToXor3E(fillMD5(md5));
        } catch (Exception e) {
            throw new RuntimeException("MD5加密错误:"+e.getMessage(),e);
        }
    }
    /**
     * 加密文件 byte[] 转为 32为 加密字符
     * @param md5
     * @return string 异或加秘 字符串
     */
    private static String stringToXor3E(String md5) {
        byte[] md5ValueHex = hex2Bytes(md5);
        for(int i = 0; i < 16; i++){
            int n = md5ValueHex[i] ^ 0x3E;
            md5ValueHex[i] = (byte)n;
        }
        return bytes2HexString(md5ValueHex);
    }
    /**
     * 十六进制byte数组转为十六进制字符串
     *
     * @param bytes 十六进制byte数组
     * @return 十六进制字符串
     */
    public static String bytes2HexString(byte[] bytes) {
        StringBuffer sb = new StringBuffer(bytes.length);
        String sTmp;

        for (int i = 0; i < bytes.length; i++) {
            sTmp = Integer.toHexString(0xFF & bytes[i]);
            if (sTmp.length() < 2) {
                sb.append(0);
            }
            sb.append(sTmp.toUpperCase());
        }

        return sb.toString();
    }
    public static String byteArrayToHexStr(byte[] byteArray) {
        if (byteArray == null) {
            return null;
        }
        char[] hexArray = "0123456789ABCDEF".toCharArray();
        char[] hexChars = new char[byteArray.length * 2];
        for (int j = 0; j < byteArray.length; j++) {
            int v = byteArray[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }
    /**
     * 十六进制转为byte数组
     *
     * @param hex 十六进制字符串
     * @return byte数组
     */
    public static byte[] hex2Bytes(String hex) {
        if (hex.length() < 1) {
            return null;
        } else {
            byte[] result = new byte[hex.length() / 2];
            int j = 0;
            for (int i = 0; i < hex.length(); i += 2) {
                result[j++] = (byte) Integer.parseInt(hex.substring(i, i + 2), 16);
            }
            return result;
        }
    }
    private static String fillMD5(String md5){
        //如果不够32位则回调自身补零，最后返回32位长度的签名
        return md5.length()==32?md5:fillMD5("0"+md5);
    }
    //1扇区的0块区存放加密串
    //IC加密
    public static String getMD5String(String str) {
        try {
            // 生成一个MD5加密计算摘要
            MessageDigest md = MessageDigest.getInstance("MD5");
            // 计算md5函数
            md.update(str.getBytes());
            // digest()最后确定返回md5 hash值，返回值为8位字符串。因为md5 hash值是16位的hex值，实际上就是8位的字符
            // BigInteger函数则将8位的字符串转换成16位hex值，用字符串来表示；得到字符串形式的hash值
            //一个byte是八位二进制，也就是2位十六进制字符（2的8次方等于16的2次方）
            return new BigInteger(1, md.digest()).toString(10);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    //IC认证
    public static boolean verifyKeys(String keys){
        String md5String = MD5Utils.getMD5String(BikeConstant.ic_keys);
        if (md5String.equals(keys)){
            return true;
        }else {
            return false;
        }
    }

    /**
     * 计算CRC16校验码
     *
     * @param bytes
     * @return
     */
    public static int getCRC(byte[] bytes,int len) {
        int CRC = 0x0000ffff;
        int POLYNOMIAL = 0x0000a001;

        int i, j;
        for (i = 0; i < len; i++) {
            CRC ^= ((int) bytes[i] & 0x000000ff);
            for (j = 0; j < 8; j++) {
                if ((CRC & 0x00000001) != 0) {
                    CRC >>= 1;
                    CRC ^= POLYNOMIAL;
                } else {
                    CRC >>= 1;
                }
            }
        }
        return CRC;
    }
}
